package com.whynot.frame.basic.util;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.util.Assert;
import org.springframework.util.*;
import org.springframework.util.PatternMatchUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.*;

/**
 * 描    述: WEB工具，获取ip地址、HttpRequest相关信息
 * 创建时间: 2018/05/22
 */
public class WebUtils {

    public final static Charset UTF8 = Charset.forName("UTF-8");

    /**
     * Default content type: "application/json".
     */
    public static final String DEFAULT_CONTENT_TYPE = "application/json";

    /**
     * Default content type for JSONP: "application/javascript".
     */
    public static final String DEFAULT_JSONP_CONTENT_TYPE = "application/javascript";

    public static final String TEMP_DIR_CONTEXT_ATTRIBUTE = "javax.servlet.context.tempdir";

    /**
     * 获取用户信息的工具类类对象
     */

    public WebUtils() {
    }

    /**
     * 描  述: 得到请求对象
     * 参  数:
     * 返回值: javax.servlet.http.HttpServletRequest
     * 创建时间: 2018/5/25
     */
    public static HttpServletRequest getRequest() {
        RequestAttributes requestAttributes = RequestContextHolder
                .getRequestAttributes();
        if (requestAttributes instanceof ServletRequestAttributes) {
            ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
            HttpServletRequest request = servletRequestAttributes.getRequest();
            return request;
        }
        return null;
    }

    /**
     * 描  述: 获取客户端IP地址
     * 参  数:
     * 返回值: java.lang.String
     * 创建时间: 2018/5/25
     */
    public static String getIpAddr() {
        HttpServletRequest request = getRequest();
        return request == null ? null : getIpAddr(request);
    }

    /**
     * 描  述: 获取客户端IP地址
     * 参  数: request
     * 返回值: java.lang.String
     * 创建时间: 2018/5/25
     */
    public static String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    /**
     * 描  述: IP是否符合规则列表
     * 参  数:patterns
     * 返回值: boolean
     * 创建时间: 2018/5/25
     */
    public static boolean isMatchIp(String[] patterns) {
        String clientIp = getIpAddr();
        return PatternMatchUtils.simpleMatch(patterns, clientIp);
    }

    /**
     * 描  述: IP是否符合规则列表
     * 参  数:patterns
     * 参  数:request
     * 返回值: boolean
     * 创建时间: 2018/5/25
     */
    public static boolean isMatchIp(String[] patterns,
                                    HttpServletRequest request) {
        String clientIp = getIpAddr(request);
        return PatternMatchUtils.simpleMatch(patterns, clientIp);
    }

    /**
     * 描  述:URL是否符合规则列表
     * 参  数:patterns
     * 参  数:request
     * 返回值: boolean
     * 创建时间: 2018/5/25
     */
    public static boolean isMatchUrl(String[] patterns, HttpServletRequest request) {
        String ctx_path = request.getContextPath();
        String request_uri = request.getRequestURI();
        String action = request_uri.substring(ctx_path.length()).replaceAll("//", "/");
        return PatternMatchUtils.simpleMatch(patterns, action);
    }

    /**
     * 描  述:根据KEY获取request的值，将数组类型的值转为LIST集合，和KEY存入MAP
     * 参  数:request
     * 返回值: org.springframework.util.MultiValueMap<java.lang.String,java.util.List<java.lang.String>>
     * 创建时间: 2018/5/25
     */
    public static MultiValueMap<String, List<String>> getMultiValueMap(
            HttpServletRequest request) {
        Map<String, String[]> paramMap = request.getParameterMap();
        MultiValueMap<String, List<String>> valueMap = new LinkedMultiValueMap<String, List<String>>();
        for (String paramKey : paramMap.keySet()) {
            String[] values = paramMap.get(paramKey);
            valueMap.add(paramKey, Arrays.asList(values));
        }
        return valueMap;
    }

    /**
     * 描  述:根据KEY获取request的对应值，把值拼接成字符串，和KEY存入MAP
     * 参  数:request
     * 返回值: java.util.Map<java.lang.String,java.lang.String>
     * 创建时间: 2018/5/25
     */
    public static Map<String, String> getSingleValueMap(
            HttpServletRequest request) {
        Map<String, String> result = new HashMap<String, String>();
        Map<String, String[]> paramMap = request.getParameterMap();
        for (String paramKey : paramMap.keySet()) {
            String[] values = paramMap.get(paramKey);
            String value = StringUtils.collectionToDelimitedString(
                    Arrays.asList(values), ",");
            result.put(paramKey, value);
        }
        return result;
    }

    /**
     * 描  述:将OBJECT以application/json 或application/javascript 输出
     * 参  数:obj
     * 参  数:request
     * 参  数:response
     * 返回值: void
     * 创建时间: 2018/5/25
     */
    public static void writeJson(Object obj, HttpServletRequest request, HttpServletResponse response)
            throws IOException {
        OutputStream out = response.getOutputStream();
        ObjectMapper mapper = new ObjectMapper();
        String text = mapper.writeValueAsString(obj);
        String jsonpFunction = getJsonpParameterValue(request);
        response.setCharacterEncoding("UTF-8");
        if (jsonpFunction != null) {
            response.setContentType(DEFAULT_JSONP_CONTENT_TYPE);
            text = jsonpFunction + "(" + text + ")";
        } else {
            response.setContentType(DEFAULT_CONTENT_TYPE);
        }
        byte[] bytes = text.getBytes(UTF8);
        out.write(bytes);
    }

    /**
     * 描  述:根据参数名 "jsonp", "callback"对应的值，即JS函数名
     * 参  数:request
     * 返回值: java.lang.String
     * 创建时间: 2018/5/25
     */
    private static String getJsonpParameterValue(HttpServletRequest request) {
        Set<String> jsonpParameterNames = new LinkedHashSet<String>(Arrays.asList("jsonp", "callback"));
        for (String name : jsonpParameterNames) {
            String value = request.getParameter(name);
            if (!StringUtils.isEmpty(value)) {
                return value;
            }
        }
        return null;
    }

    /**
     * 描  述: 流形式下载文件
     * 参  数:response
     * 参  数:in
     * 参  数:fileName
     * 返回值: void
     * 创建时间: 2018/5/25
     */
    public static void download(HttpServletResponse response, InputStream in,
                                String fileName,HttpServletRequest request) throws IOException {


        response.setContentType("text/html;charset=UTF-8");
        request.setCharacterEncoding("UTF-8");

        String header = request.getHeader("User-Agent").toUpperCase();
        if (header.contains("MSIE") || header.contains("TRIDENT") || header.contains("EDGE")) {
            fileName = URLEncoder.encode(fileName, "utf-8");
            fileName = fileName.replace("+", "%20");    //IE下载文件名空格变+号问题
        } else {
            fileName = new String(fileName.getBytes(), "ISO8859-1");
        }

//        String attachName = new String(fileName.getBytes("UTF-8"), "ISO-8859-1");
        // 1.设置文件ContentType类型，这样设置，会自动判断下载文件类型
        response.setContentType("multipart/form-data");
        response.setHeader("Content-disposition", "attachment; filename="
                + fileName);
        ServletOutputStream out = response.getOutputStream();
        BufferedInputStream bis = new BufferedInputStream(in);
        BufferedOutputStream bos = new BufferedOutputStream(out);
        byte[] buff = new byte[2048];
        int bytesRead;
        while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
            bos.write(buff, 0, bytesRead);
        }
        bis.close();
        bos.close();
    }

    public static void download(HttpServletResponse response, InputStream in,
                                String fileName) throws IOException {
        String attachName = new String(fileName.getBytes("UTF-8"), "ISO-8859-1");
        // 1.设置文件ContentType类型，这样设置，会自动判断下载文件类型
        response.setContentType("multipart/form-data");
        response.setHeader("Content-disposition", "attachment; filename="
                + attachName);
        ServletOutputStream out = response.getOutputStream();
        BufferedInputStream bis = new BufferedInputStream(in);
        BufferedOutputStream bos = new BufferedOutputStream(out);
        byte[] buff = new byte[2048];
        int bytesRead;
        while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
            bos.write(buff, 0, bytesRead);
        }
        bis.close();
        bos.close();
    }

    /**
     * 描  述: 流形式输出显示，输入流读取的文件内容
     * 参  数:response
     * 参  数:in
     * 参  数:fileName
     * 参  数:contentType
     * 返回值: void
     * 创建时间: 2018/5/25
     */
    public static void view(HttpServletResponse response, InputStream in,
                            String fileName, String contentType) throws IOException {
        response.setContentType(contentType);
        ServletOutputStream out = response.getOutputStream();
        BufferedInputStream bis = new BufferedInputStream(in);
        BufferedOutputStream bos = new BufferedOutputStream(out);
        byte[] buff = new byte[2048];
        int bytesRead;
        while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
            bos.write(buff, 0, bytesRead);
        }
        bis.close();
        bos.close();
    }

    public static File getTempDir(ServletContext servletContext) {
        Assert.notNull(servletContext, "ServletContext must not be null");
        return (File) servletContext.getAttribute(WebUtils.TEMP_DIR_CONTEXT_ATTRIBUTE);
    }

    public static String urlencoder(String str, String enc) {
        String encStr = null;
        try {
            encStr = URLEncoder.encode(str, enc);
        } catch (Exception e) {
            return "";
        }
        return encStr;
    }
}
